package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.stream.CollectorUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.UserPaidAlbum;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.model.user.UserVipService;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper;
import com.atguigu.tingshu.user.mapper.UserVipServiceMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.user.service.UserPaidTrackService;
import com.atguigu.tingshu.user.strategy.OrderSrategy;
import com.atguigu.tingshu.user.strategy.StragetyFactoryBean;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	@Autowired
	private UserInfoMapper userInfoMapper;

	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private RabbitService rabbitService;
	@Autowired
	private WxMaService wxMaService;
	@Autowired
	private UserPaidTrackMapper paidTrackMapper;
	@Autowired
	private UserPaidAlbumMapper paidAlbumMapper;
	@Autowired
	private  UserPaidAlbumMapper userPaidAlbumMapper;
	@Autowired
	private UserPaidTrackMapper userPaidTrackMapper;
	@Autowired
	private UserVipServiceMapper userVipServiceMapper;

	@Override
	@SneakyThrows
	public Map<String, String> wxLogin(String code) {
		//已经拿到了用户的code 通过wx
		WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
		if (sessionInfo!=null){
		String openid = sessionInfo.getOpenid();
		UserInfo userInfo = baseMapper.selectOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getWxOpenId, openid));
		if (userInfo==null){
			//2.2 为首次登录用户构建用户对象，保存用户记录
			userInfo = new UserInfo();
			userInfo.setWxOpenId(openid);
			userInfo.setNickname("听友" + IdUtil.getSnowflakeNextId());
			userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
			userInfo.setIsVip(0);
			userInfo.setVipExpireTime(new Date());
			userInfoMapper.insert(userInfo);
			//2.3 发送Kafka异步消息，通知账户微服务新增账户记录
			rabbitService.sendMessage(MqConst.EXCHANGE_USER,MqConst.ROUTING_USER_REGISTER,userInfo.getId());
		}
			//3.基于用户记录生成Token 将用户令牌存入Redis Key:前缀+token  Value:用户信息UserInfoVo
			String token = IdUtil.fastUUID();
			String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
			UserInfoVo userInfoVo = BeanUtil.copyProperties(userInfo, UserInfoVo.class);
			redisTemplate.opsForValue().set(loginKey,userInfoVo, RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);
			//4.将用户token封装结果返回
			Map<String, String> mapResult = new HashMap<>();
			mapResult.put("token", token);
			return mapResult;
		}
		return null;
	}

	@Override
	public void updateUser(Long userId, UserInfoVo userInfoVo) {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) requestAttributes;
		String token = sra.getRequest().getHeader("token");
		UserInfo userInfo = baseMapper.selectById(userId);
		Assert.notNull(userInfo,"无法获取到用户数据");
		userInfo.setAvatarUrl(userInfoVo.getAvatarUrl());
		userInfo.setNickname(userInfoVo.getNickname());
		userInfo.setId(userId);
		baseMapper.updateById(userInfo);
		BeanUtils.copyProperties(userInfo,userInfoVo);
		String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;

		redisTemplate.opsForValue().set(loginKey,userInfoVo, RedisConstant.USER_LOGIN_KEY_TIMEOUT,TimeUnit.SECONDS);
	}

    @Override
    public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needChackTrackIdList) {
        //已知 用户ID 专辑ID 需要查询声音是否购买列表
		//查询用户购买信息 判断哪些声音需要付费 哪些为购买
		//通过map数据 声音ID为key 付费属性为value
		Map<Long,Integer> map = new HashMap<>();
		Long count = paidAlbumMapper.selectCount(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userId).eq(UserPaidAlbum::getAlbumId, albumId));
		if (count > 0) {
			for (Long checkTrackId : needChackTrackIdList) {
				map.put(checkTrackId,1);
			}
			return map;
		}
		List<UserPaidTrack> userPaidTracks = paidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getAlbumId, albumId).eq(UserPaidTrack::getUserId, userId));
		List<Long> paidTrackIds = userPaidTracks.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
		if (CollectionUtil.isEmpty(paidTrackIds)){
			for (Long needCheckTrackId : needChackTrackIdList) {
				map.put(needCheckTrackId,0);
			}
			return map;
		}

		for (Long needCheckTrackId : needChackTrackIdList) {
			if (paidTrackIds.contains(needCheckTrackId)){
				map.put(needCheckTrackId,1);
			}else
			{
			map.put(needCheckTrackId,0);

			}
		}
		return map;
	}

	/**
	 * 验证当前用户是否购买过专辑
	 *
	 * @param albumId
	 * @return
	 */
	@Override
	public Boolean isPaidAlbum(Long albumId) {
		//1.获取当前用户ID
		Long userId = AuthContextHolder.getUserId();
		//2.构建查询条件：用户ID+专辑ID 查询专辑购买记录表
		LambdaQueryWrapper<UserPaidAlbum> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(UserPaidAlbum::getUserId, userId);
		queryWrapper.eq(UserPaidAlbum::getAlbumId, albumId);
		Long count = userPaidAlbumMapper.selectCount(queryWrapper);
		return count > 0;
	}

	/**
	 * 根据用户ID+专辑ID查询已购声音集合
	 *
	 * @param userId  用户ID
	 * @param albumId 专辑ID
	 * @return
	 */
	@Override
	public List<Long> getUserPaidTrackIdList(Long userId, Long albumId) {
		//1.根据用户ID+专辑ID查询已购声音集合
		LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(UserPaidTrack::getUserId, userId);
		queryWrapper.eq(UserPaidTrack::getAlbumId, albumId);
		List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(queryWrapper);
		if (CollectionUtil.isNotEmpty(userPaidTrackList)) {
			//2.获取已购声音ID集合
			List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
			return userPaidTrackIdList;
		}
		return null;
	}

	@Override
	public void saveUserVip(UserVipService userVipService) {
		userVipServiceMapper.insert(userVipService);
		UserInfo userInfo = userInfoMapper.selectById(userVipService.getUserId());
		userInfo.setVipExpireTime(userVipService.getExpireTime());
		userInfo.setIsVip(1);
		userInfoMapper.updateById(userInfo);
	}

	@Override
	public void saveUserPaidTrack(UserPaidTrack userPaidTrack) {
		userPaidTrackMapper.insert(userPaidTrack);
	}

	@Autowired
	private StragetyFactoryBean strategyFactory;



	/**
	 * 处理用户购买记录（虚拟物品发货）
	 *userPaidRecordVo.getItemType()  1001  1002  1003
	 * @param userPaidRecordVo 购买记录VO
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {
		//从策略工厂中获取对应的策略对象
		OrderSrategy strategy = strategyFactory.getStrategy(userPaidRecordVo.getItemType());
		//执行策略对象的任务
		strategy.submitOrderStrategy(userPaidRecordVo);
	}

}
